package cate.game.role.res.leader.hallows;

import cate.common.table.d.GDHallows;
import cate.common.table.d.GDOperation;
import cate.common.table.hallow.HallowHallucinateRow;
import cate.common.table.hallow.row.HallowHolySealRow;
import cate.common.table.hallow.row.HallowLevelUpRow;
import cate.common.table.hallow.row.HallowRefineRow;
import cate.common.table.hallow.row.HallowSkillRow;
import cate.common.util.GameResult;
import cate.game.GameBody;
import cate.game.attr.FightAttr;
import cate.game.play.support.PlayBuildContext;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.res.leader.hallows.msg.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

import java.util.ArrayList;
import java.util.List;

@NoteClass(value = "单个圣器的数据")
public class Hallow extends RoleDependent {
  @NoteField(value = "圣器类型")
  public int type;

  @NoteField(value = "副圣器类型")
  public int deputyType;

  @NoteField(value = "淬炼阶段")
  public int grade;

  @NoteField(value = "淬炼次数")
  public int times;

  @NoteField(value = "皮肤ID", detail = "0为没有皮肤")
  public int skinId;

  @NoteField(value = "技能")
  public HallowSkill skill;

  @NoteField(value = "圣印")
  public HallowHolySeal holySeal;

  @NoteField(value = "精炼")
  public HallowRefine refineSkill;


  public Hallow() {
  }

  public Hallow(Role role, int type) {
    super(role);
    this.type = type;
    this.grade = 1;
  }

  @Override
  public void initialize(Role role) {
    super.initialize(role);
    if (skill == null) {
      HallowSkillRow skillRow = role.getGame().table.hallow.skill.getRowByTypeAndLevel(type, 1);
      if (skillRow == null) {
        return;
      }
      skill = new HallowSkill(this.type, 1, skillRow.skillId);
    }
    if (holySeal == null) {
      HallowHolySealRow holySealRow = role.getGame().table.hallow.holySeal.getRowByTypeAndLevel(type, 1);
      if (holySealRow == null) {
        return;
      }
      holySeal = new HallowHolySeal(this.type, 0);
    }
    if (refineSkill == null) {
      HallowRefineRow refineRow = role.getGame().table.hallow.refineSkill.getRowByTypeAndLevel(type, 1);
      if (refineRow == null) {
        return;
      }
      refineSkill = new HallowRefine(this.type, 0);
    }
  }

  @Override
  public void onEnter() {
    checkAutoUpgrade();
  }

  public void checkAutoUpgrade() {
    HallowLevelUpRow nextRow = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(type, grade + 1);
    if (nextRow != null) {
      HallowLevelUpRow nowRow = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(type, grade);
      if (nowRow != null && times * nowRow.value >= nowRow.maxValue) {
        grade++;
        times = 0;
      }
    }
  }

  public GameResult upgradeSkill() {
    GameResult result = new GameResult<>();

    HallowSkillRow skillRow = role.getGame().table.hallow.skill.getRowByTypeAndLevel(type, this.skill.level);
    if (skillRow == null || isSkillTopLevel(skillRow)) {
      return result.fail("无法继续升级该技能");
    }
    HallowSkillRow nextSkillRow = role.getGame().table.hallow.skill.getRowByTypeAndLevel(type, this.skill.level + 1);
    if (nextSkillRow == null) {
      result.fail("无法继续升级该技能");
    }
    if (nextSkillRow.levelRequire > grade) {
      return result.fail(310042, "", nextSkillRow.levelRequire);
    }
    MixRes cost = new MixRes(skillRow.consumeStr);
    GameResult<MixResItem> consumeRes = cost.consumeCheck(role, null);
    if (!consumeRes.ok()) {
      role.getGame().notice.tipResItem(role, consumeRes.data);
      return result.fail(consumeRes);
    }
    cost.consume(role);
    skill.level = nextSkillRow.level;
    skill.chooseSkill = nextSkillRow.skillId;
    noticeSkill(skill);
    return result;
  }

  @JsonIgnore
  public boolean isSkillTopLevel(HallowSkillRow row) {
    if (row == null) {
      return true;
    }
    return row.isTopLevel;
  }

  @JsonIgnore
  public List<Integer> getSkills(PlayBuildContext ctx, boolean deputy) {
    List<Integer> list = new ArrayList<>();
    HallowSkillRow skillRow = ctx.hallowExcel().skill.getRowByTypeAndLevel(type, this.skill.level);
    if (skillRow != null) {
      if (deputy) {
        list.add(skillRow.deputySkillId);
      } else {
        list.add(skillRow.skillId);
      }
    }
    return list;
  }

  public GameResult<Boolean> quenching() {
    GameResult<Boolean> result = new GameResult<>();
    //根据等级和类型获取row
    HallowLevelUpRow baseRow = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(type, grade);
    HallowLevelUpRow nextBaseRow = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(type, grade + 1);
    if (baseRow == null || nextBaseRow == null) {
      return result.fail("该圣器不可继续升级");
    }
    boolean willMaxDegree = (times + 1) * baseRow.value >= baseRow.maxValue;
    boolean lastDegree = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(type, grade + 1) == null;
    MixRes consumeItem = new MixRes(baseRow.consumeStr);
    consumeItem.addList(new MixRes(baseRow.consumeM1Str));
    GameResult<MixResItem> consumeRes = consumeItem.consume(role, null);
    if (!consumeRes.ok()) {
      role.getGame().notice.tipResItem(role, consumeRes.data);
      return result.fail(consumeRes.message);
    }
    if (willMaxDegree && !lastDegree) {
      grade++;
      times = 0;
      role.getHistory().action.hallowLevelUp();
    } else {
      times++;
    }
    result.data = willMaxDegree;
    noticeQuenching(willMaxDegree, type, grade, times);
    return result;
  }

  @JsonIgnore
  public FightAttr getAttr(GameBody game) {
    FightAttr attr = new FightAttr();
    HallowLevelUpRow baseRow;
    HallowSkillRow skillRow;
    //圣器淬炼属性加成
    if (this.grade > 1) {
      baseRow = game.table.hallow.levelUp.getHallowByTypeAndGrade(this.type, this.grade);
      if (baseRow != null) {
        attr.add(new FightAttr(baseRow.attrStr));
      }
    }
    if (this.times > 0) {
      baseRow = game.table.hallow.levelUp.getHallowByTypeAndGrade(this.type, this.grade);
      if (baseRow != null) {
        attr.add(new FightAttr(baseRow.attrStageStr).scale(this.times * baseRow.value / baseRow.realValue));
      }
    }
    //圣器技能属性加成
    if (this.skill != null) {
      skillRow = game.table.hallow.skill.getRowByTypeAndLevel(this.type, skill.level);
      if (skillRow != null) {
        attr.add(new FightAttr(skillRow.attrStr));
      }
    }

    //圣器圣印加成
    if (this.times > 0) {
      HallowHolySealRow holySealRow = game.table.hallow.holySeal.getRowByTypeAndLevel(this.type, this.grade);
      if (holySealRow != null) {
        attr.add(new FightAttr(holySealRow.attrStr));
      }
    }
    return attr;
  }

  public double getSkillDamage(PlayBuildContext ctx, boolean deputy) {
    double damage = 0d;
    //副圣器没有基础伤害
    if (!deputy) {
      HallowSkillRow skillRow = ctx.hallowExcel().skill.getRowByTypeAndLevel(type, this.skill.level);
      if (skillRow != null) {
        damage += skillRow.damage;
      }
    }
    HallowRefineRow refineRow = ctx.hallowExcel().refineSkill.getRowByTypeAndLevel(type, refineSkill.level);
    if (refineRow != null) {
      damage += refineRow.hurt;
    }
    return damage;
  }

  public void noticeQuenching(boolean gradeUp, int type, int grade, int times) {
    role.sendNow(new HallowsQuenchingResp(gradeUp, type, grade, times));
  }

  public void noticeUnlock() {
    role.sendNow(new HallowsUnlockResp(this));
  }

  public void noticeSkill(HallowSkill skill) {
    role.sendNow(new HallowsUpgradeSkillResp(skill));
  }


  public Hallow copy() {
    Hallow cp = new Hallow();
    cp.type = this.type;
    cp.deputyType = this.deputyType;
    cp.grade = this.grade;
    cp.times = this.times;
    cp.skinId = this.skinId;
    cp.skill = this.skill.copy();
    return cp;
  }

  public void gmReset() {
    this.grade = 1;
    this.times = 0;
  }

  public GameResult<Void> upgradeHolySeal() {
    GameResult<Void> result = new GameResult<>();
    HallowHolySealRow holySealRow = role.getGame().table.hallow.holySeal.getRowByTypeAndLevel(type, this.holySeal.level);
    HallowHolySealRow nextSealRow = role.getGame().table.hallow.holySeal.getRowByTypeAndLevel(type, this.holySeal.level + 1);
    if (holySealRow == null || nextSealRow == null) {
      return result.fail("无法继续升级该圣印");
    }

    if (nextSealRow.levelRequire >  grade) {
      return result.fail(310044, nextSealRow.levelRequire);
    }

    MixRes cost = new MixRes(holySealRow.consumeStr);
    GameResult<MixResItem> consume_r = cost.consumeCheck(role, null);
    if (!consume_r.ok()) {
      role.getGame().notice.tipResItem(role, consume_r.data);
      return result.fail(consume_r.message);
    }
    cost.consume(role);
    holySeal.level = nextSealRow.level;
    noticeHolySeal(holySeal);
    return result;
  }

  private void noticeHolySeal(HallowHolySeal holySeal) {
    role.sendNow(new HallowsHolySealUpgradeResp(holySeal));
  }

  public GameResult<Void> refineSkill() {
    GameResult<Void> result = new GameResult<>();
    HallowRefineRow refineRow = role.getGame().table.hallow.refineSkill.getRowByTypeAndLevel(type, this.refineSkill.level);
    HallowRefineRow nextRefineRow = role.getGame().table.hallow.refineSkill.getRowByTypeAndLevel(type, this.refineSkill.level + 1);
    if (refineRow == null || nextRefineRow == null) {
      return result.fail("无法继续精炼");
    }

    if (nextRefineRow.hallowLevelRequire > grade) {
      return result.fail(310043, nextRefineRow.hallowLevelRequire);
    }

    MixRes cost = new MixRes(refineRow.consumeStr);
    GameResult<MixResItem> consume_r = cost.consumeCheck(role, null);
    if (!consume_r.ok()) {
      role.getGame().notice.tipResItem(role, consume_r.data);
      return result.fail(consume_r.message);
    }
    cost.consume(role);
    refineSkill.level = nextRefineRow.level;
    noticeRefine(refineSkill);
    return result;
  }

  private void noticeRefine(HallowRefine refine) {
    role.sendNow(new HallowsRefineResp(refine));
  }

  /**
   * 幻化
   *
   * @param skinId
   * @return
   */
  public GameResult<Void> hallucinate(int skinId) {
    GameResult<Void> result = new GameResult<>();
    HallowHallucinateRow hallucinateRow = role.getGame().table.hallow.hallucinate.get(skinId);
    if (hallucinateRow == null) {
      return result.fail("不存在该皮肤");
    }
    this.skinId = skinId;
    noticeSkin(this.type, skinId);
    return result;
  }

  private void noticeSkin(int type, int skinId) {
    role.sendNow(new HallowsHallucinateResp(type, skinId));
  }

  /**
   * 设置副圣器
   *
   * @param deputyType
   * @return
   */
  public GameResult<Void> setDeputyHallow(int deputyType) {
    GameResult<Void> result = new GameResult<>();

    if (this.grade < GDHallows.DEPUTY_HALLOW_OPEN_GRADE_LIMIT) {
      return result.fail(String.format("需要圣器到达%d级", GDHallows.DEPUTY_HALLOW_OPEN_GRADE_LIMIT));
    }
    if (this.type == deputyType) {
      return result.fail("不能设置自己为自己的副圣器");
    }
    this.deputyType = deputyType;
    noticeDeputy();
    return result.success();
  }

  private void noticeDeputy() {
    role.sendNow(new HallowsSetDeputyResp(this.type, this.deputyType));
  }

  /**
   * 圣器重铸
   *
   * @return
   */
  public GameResult<Void> backHallow() {
    GameResult<Void> result = new GameResult<>();
    if (this.grade < 2) {
      return result.fail("该圣器不需要重铸 ");
    }
    MixRes reward = new MixRes();

    HallowLevelUpRow row = role.getGame().table.hallow.levelUp.getHallowByTypeAndGrade(this.type, this.grade);
    reward.addList(new MixRes(row.consumeStr).multiply(times));
    reward.addList(new MixRes(row.backStr));
    this.grade = 1;
    this.deputyType = 0;
    this.skinId = 0;
    this.times = 0;

    reward.addList(this.skill.back(role.getGame()));
    reward.addList(this.holySeal.back(role.getGame()));
    reward.addList(this.refineSkill.back(role.getGame()));
    role.getGame().notice.dialogReward(role, reward);
    reward.add(role, true, GDOperation.HALLOWS_BACK);
    noticeHallow();
    return result.success();
  }

  private void noticeHallow() {
    role.sendNow(new HallowsSingleDataResp(this));
  }
}
